package com.pactera.madp.cp.context;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.pactera.madp.cp.common.annotations.SyncType;
import com.pactera.madp.cp.common.enums.sync.SyncTypeEnum;
import com.pactera.madp.cp.handler.sync.SyncTypeHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 策略模式，处理type与实现类的映射关系
 */
@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {
    /**
     * 扫描@SyncType注解，初始化HandlerContext,将其注册到Spring容器
     *
     * @param configurableListableBeanFactory bean工厂
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        Map<String, SyncTypeHandler> handlerMap = new HashMap<>();
        for (SyncTypeEnum item : SyncTypeEnum.values()) {
            SyncTypeHandler handler = getBeansWithAnnotation(
                    configurableListableBeanFactory,
                    SyncTypeHandler.class,
                    SyncType.class,
                    item.getCode());
            handlerMap.put(item.getCode(), handler);
        }
        HandlerContext context = new HandlerContext(handlerMap);
        // 单例注入
        configurableListableBeanFactory.registerSingleton(HandlerContext.class.getName(), context);
    }

    /**
     * 通过父类+注解找到实体类
     * @param beanFactory   bean工厂
     * @param manager
     * @param annotation    要查找的注解
     * @param code
     * @param <T>
     * @return
     */
    private <T> T getBeansWithAnnotation(ConfigurableListableBeanFactory beanFactory,
                                         Class<T> manager,
                                         Class<? extends SyncType> annotation,
                                         String code) {
        if (StrUtil.isBlank(code)) {
            throw new IllegalArgumentException("[code]参数不能为空");
        }
        Collection<T> collection = beanFactory.getBeansOfType(manager).values();
        for (T t : collection) {
            SyncType orderType = t.getClass().getAnnotation(annotation);
            if (ObjectUtil.isNull(orderType)) {
                throw new IllegalArgumentException("该注解没有写入值：" + code);
            }
            // 注解值是否与code相等
            if (StrUtil.equals(code, orderType.value().getCode())) {
                return t;
            }
        }
        throw new IllegalArgumentException("通过[code]没有找到该注解对应的实体类：" + code);
    }
}
